package com.mt.common.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mt.common.core.config.Config;
import com.mt.common.core.exception.BusinessException;
import com.mt.common.core.security.LoginUser;
import com.mt.common.core.utils.WxUtil;
import com.mt.common.core.web.JsonResult;
import com.mt.common.core.web.PageParam;
import com.mt.common.core.web.SecurityExpression;
import com.mt.common.system.entity.Menu;
import com.mt.common.system.entity.Role;
import com.mt.common.system.entity.User;
import com.mt.common.system.entity.UserRole;
import com.mt.common.system.mapper.MenuMapper;
import com.mt.common.system.mapper.UserMapper;
import com.mt.common.system.mapper.UserRoleMapper;
import com.mt.common.system.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 用户服务实现类
 * Created by wangfan on 2018-12-24 16:10
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Autowired
    private UserRoleMapper userRoleMapper;
    @Autowired
    private MenuMapper menuMapper;
    @Autowired
    private UserMapper userMapper;

    @Resource
    private RedisTemplate<String, LoginUser> redisTemplate;

    @Override
    public User getByUsername(String username) {
        return baseMapper.selectOne(new QueryWrapper<User>().eq("username", username));
    }

    @Override
    public LoginUser getByOpenID(String openId) {
        LoginUser loginUser=null;
        User user = this.getFullByOpenId(openId);

        if (user == null) return null;
        //user = this.selectUserAuth(user);

        loginUser = LoginUser.create(user);
        loginUser.setCached(false);

        return  loginUser;
    }

    private User getFullByOpenId(String openId) {
        User user = baseMapper.selectOne(new QueryWrapper<User>().eq("open_id", openId));
        if(null==user){
            return null;
        }
        return selectRoleAndAuth(user);
    }

    @Override
    public User getFullById(Long userId) {
        List<User> userList = baseMapper.listAll(new PageParam<User>().put("eid", userId).getNoPageParam());
        if (userList == null || userList.size() == 0) return null;
        return selectRoleAndAuth(userList.get(0));
    }

    @Override
    public User getUserById(Long eid) {
        List<User> userList = baseMapper.listAll(new PageParam<User>().put("eid", eid).getNoPageParam());
        if (userList == null || userList.size() == 0) return null;
        return userList.get(0);
    }

    @Override
    public User getFullByUsername(String username) {
        List<User> userList = baseMapper.listAll(new PageParam<User>().put("username", username).getNoPageParam());
        if (userList == null || userList.size() == 0) return null;
        return selectRoleAndAuth(userList.get(0));
    }

    @Override
    public User selectRoleAndAuth(User user) {
        if (user == null) return user;
        user.setRoles(userRoleMapper.listByUserId(user.getEid()));
        return selectUserAuth(user);
    }
    @Override
    public User selectRoles(User user) {
        if (user == null) return user;
        user.setRoles(userRoleMapper.listByUserId(user.getEid()));
        return user;
    }
    @Override
    public User selectUserAuth(User user) {
        if (user == null) return user;
        List<Menu> menus = menuMapper.listAuthoritiesByUserId(user.getEid());

//        List<Menu> authList = new ArrayList<>();
//        for (Menu menu : menus) {
//            if (StrUtil.isNotBlank(menu.getAuthority())) {
//                authList.add(menu);
//            }
//        }
        user.setAuthorities(menus);
        return user;
    }

    @Override
    public List<User> listPage(PageParam<User> page) {
        List<User> users = baseMapper.listPage(page);
        // 查询用户的角色
        selectUserRoles(users);
        return users;
    }

    @Override
    public List<User> listAll(Map<String, Object> page) {
        List<User> users = baseMapper.listAll(page);
        // 查询用户的角色
        selectUserRoles(users);
        return users;
    }

    @Transactional
    @Override
    public boolean saveUser(User user) {
        if (user.getUsername() != null && baseMapper.selectCount(new QueryWrapper<User>()
                .eq("username", user.getUsername())) > 0) {
            throw new BusinessException("账号已存在");
        }
        if (user.getPhone() != null && baseMapper.selectCount(new QueryWrapper<User>()
                .eq("phone", user.getPhone())) > 0) {
            throw new BusinessException("手机号已存在");
        }
        if (user.getEmail() != null && baseMapper.selectCount(new QueryWrapper<User>()
                .eq("email", user.getEmail())) > 0) {
            throw new BusinessException("邮箱已存在");
        }
        boolean result = baseMapper.insert(user) > 0;
        if (result) {
            addUserRoles(user.getEid(), user.getRoleIds(), false);
        }
        return result;
    }

    @Transactional
    @Override
    public boolean updateUser(User user) {
        if (user.getUsername() != null && baseMapper.selectCount(new QueryWrapper<User>()
                .eq("username", user.getUsername()).ne("eid", user.getEid())) > 0) {
            throw new BusinessException("账号已存在");
        }
        if (user.getPhone() != null && baseMapper.selectCount(new QueryWrapper<User>()
                .eq("phone", user.getPhone()).ne("eid", user.getEid())) > 0) {
            throw new BusinessException("手机号已存在");
        }
        if (user.getEmail() != null && baseMapper.selectCount(new QueryWrapper<User>()
                .eq("email", user.getEmail()).ne("eid", user.getEid())) > 0) {
            throw new BusinessException("邮箱已存在");
        }
        boolean result = baseMapper.updateById(user) > 0;
        if (result&&user.getRoleIds()!=null) {
            addUserRoles(user.getEid(), user.getRoleIds(), true);
        }
        return result;
    }
    @Override
    public boolean comparePsw(String dbPsw, String inputPsw) {
        return dbPsw != null && new BCryptPasswordEncoder().matches(inputPsw, dbPsw);
    }

    public static void main(String[] args) {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String encode = bCryptPasswordEncoder.encode("123456");
        System.out.println(new BCryptPasswordEncoder().matches("123456", "$2a$10$OAJ0uLTKBFmWEiz.TC27JuswGi4TPq3jq3NM9ikq.SlB7stzhgZHK"));

    }
    @Override
    public String encodePsw(String psw) {
        if (psw == null) return null;
        return new BCryptPasswordEncoder().encode(psw);
    }

    /**
     * 查询所有User集合
     * @return
     */
    @Override
    public List<User> findAllUsersWithIdName() {
        return userMapper.findAllUsersWithIdName();
    }

    @Override
    public LoginUser loadFromCache(String username) {
        return this.loadFromCache(username,false);
    }
    @Override
    public LoginUser loadFromCache(String username,boolean force) {
        LoginUser loginUser  = null;
        if(!force) {
            loginUser = (LoginUser) redisTemplate.opsForValue().get("user:" + username);
            if (loginUser != null){
                loginUser.setCached(true);
                return loginUser;
            }
        }

        User user = this.getFullByUsername(username);

        if (user == null) throw new UsernameNotFoundException("没有找到名为 "+username+" 的用户");
        //user = this.selectUserAuth(user);

        loginUser = LoginUser.create(user);
        loginUser.setCached(false);

        return  loginUser;

    }
    @Override
    public void cache(LoginUser user)
    {
        //TODO: 写入redis
        redisTemplate.opsForValue().set("user:"+user.getUsername(), user, Config.tokenExpireTime, TimeUnit.MILLISECONDS);
    }
    @Override
    public void resetCache(String username) {
            redisTemplate.boundValueOps("user:"+username).expire(Config.tokenExpireTime, TimeUnit.MILLISECONDS);
    }

    @Override
    public void decache() {
        Set<String> keys = redisTemplate.keys("user:*");
        redisTemplate.delete(keys);
    }

    @Override
    public void decache(String username) {
        redisTemplate.delete("user:"+username);
    }

    /**
     * 批量查询用户的角色
     */
    private void selectUserRoles(List<User> users) {
        if (users != null && users.size() > 0) {
            List<Long> userIds = users.stream().map(User::getEid).collect(Collectors.toList());
            List<Role> userRoles = userRoleMapper.listByUserIds(userIds);
            for (User user : users) {
                List<Role> roles = userRoles.stream().filter(d -> user.getEid().equals(d.getEid())).collect(Collectors.toList());
                user.setRoles(roles);
            }
        }
    }

    /**
     * 添加用户角色
     */
    private void addUserRoles(Long userId, List<Long> roleIds, boolean deleteOld) {
        if (deleteOld) {
            userRoleMapper.delete(new UpdateWrapper<UserRole>().eq("user_id", userId));
        }
        if (userRoleMapper.insertBatch(userId, roleIds) < roleIds.size()) {
            throw new BusinessException("操作失败");
        }
    }

    @Override
    public List<User> getUserIdByRoleId(List<Long> roleIds) {
        return userMapper.getUserIdByRoleId(roleIds);
    }

    @Override
    public JsonResult updatePasswordByEid(Long eid, String oldPassword, String newPassword) {
        User user = baseMapper.listAll(new PageParam<User>().put("eid", eid).getNoPageParam()).get(0);
        //老密码匹配
        boolean isPas = comparePsw(user.getPassword(), oldPassword);
        if(!isPas){ return JsonResult.error("原密码错误");}
        if(oldPassword.equals(newPassword)){return JsonResult.error("原密码不可与新密码相同");}
        String encodedPassword=encodePsw(newPassword);
        this.userMapper.updatePasswordById(eid,encodedPassword);

        return JsonResult.ok("密码修改成功");
    }
    @Autowired
    WxUtil wxUtil;
    @Override
    public JsonResult bindWx(String code,Long userId) {
        String openId=wxUtil.getOpenId(code);
        //判断当前用户是否已经绑定用户
        User user = baseMapper.selectOne(new QueryWrapper<User>().eq("open_id", openId));

        if(user!=null){
            return JsonResult.error("绑定操作失败,原因是已经绑定账号:"+user.getUsername());
        }

        Long rows=this.userMapper.bindWx(openId,userId);
        if(rows!=1){
            return JsonResult.error("绑定操作失败");
        }
        JsonResult result = JsonResult.ok("绑定成功");
        result.put("openId",openId);
        return result;
    }

    @Override
    public JsonResult removeWx(Long userId) {
        Long rows=this.userMapper.removeWx(userId);
        if(rows!=1){
            return JsonResult.error("解除微信失败");
        }
        JsonResult result = JsonResult.ok("解除微信绑定成功");
        return result;
    }
}
